package com.oazon.analytics;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

import android.content.Context;

import com.oazon.common.Assert;
import com.oazon.common.Settings;

public class AnalyticsManager implements IAnalyticsCollector {
    private static final String TAG = "AnalyticsManager";

    List<IAnalyticsCollector> mAnalyticsCollectors = new ArrayList<IAnalyticsCollector>();

    private static AnalyticsManager mInstance = null;
    private static boolean mIsInitialized = false;

    public static boolean SDK = false;
    private static final int DEFAULT_RANDOM_RATE = 100;

    public static AnalyticsManager getInsance() {
        if (mInstance == null)
            mInstance = new AnalyticsManager();
        return mInstance;
    }

    /**
     * check if already initialized.
     */
    public boolean isInitialized() {
        return mIsInitialized;
    }

    /**
     * init analytics manager.
     * @param context
     * @param collectors all the analytics collector to be used.
     */
    public void init(Context context, Collection<? extends IAnalyticsCollector> collectors) {
        if (mIsInitialized)
            return;
        mIsInitialized = true;
        mAnalyticsCollectors.addAll(collectors);
        updateOnlineConfig(context);
        onError(context);
    }

    public static void destroy() {
        mInstance.mAnalyticsCollectors.clear();
        mInstance.mAnalyticsCollectors = null;
        mIsInitialized = false;
        mInstance = null;
    }

    @Override
    public void updateOnlineConfig(Context context) {
        Assert.isTrue(mIsInitialized);
        for (IAnalyticsCollector collector : mAnalyticsCollectors)
            collector.updateOnlineConfig(context);
    }

    @Override
    public void onError(Context context) {
        Assert.isTrue(mIsInitialized);
        for (IAnalyticsCollector collector : mAnalyticsCollectors)
            collector.onError(context);
    }

    @Override
    public void onResume(Context context) {
        Assert.isTrue(mIsInitialized);
        for (IAnalyticsCollector collector : mAnalyticsCollectors)
            collector.onResume(context);
    }

    @Override
    public void onPause(Context context) {
        Assert.isTrue(mIsInitialized);
        for (IAnalyticsCollector collector : mAnalyticsCollectors)
            collector.onPause(context);
    }

    @Override
    public void onEvent(Context context, String eventId) {
        Assert.isTrue(mIsInitialized);
        for (IAnalyticsCollector collector : mAnalyticsCollectors)
            collector.onEvent(context, eventId);
    }

    public void onRandomEvent(Context context, String eventId) {
        onRandomEvent(context, eventId, DEFAULT_RANDOM_RATE);
    }

    // Rate is random collect rate, if the rate is m, then the event collect rate is 1/m.
    public void onRandomEvent(Context context, String eventId, int rate) {
        Assert.isTrue(mIsInitialized);
        if (isRandomCollect(rate)) {
            for (IAnalyticsCollector collector : mAnalyticsCollectors)
                collector.onEvent(context, eventId);
        }
    }

    @Override
    public void onEvent(Context context, String eventId, String label) {
        Assert.isTrue(mIsInitialized);
        for (IAnalyticsCollector collector : mAnalyticsCollectors)
            collector.onEvent(context, eventId, label);
    }

    public void onOnceEvent(Context context, String eventId, String label) {
        Assert.isTrue(mIsInitialized);
        Settings settings = new Settings(context);
        String key = "Analytics" + eventId;
        boolean hasReport = settings.getBoolean(key, false);
        if (!hasReport) {
            for (IAnalyticsCollector collector : mAnalyticsCollectors)
                collector.onEvent(context, eventId, label);
            settings.setBoolean(key, true);
        }
    }

    public void onRandomEvent(Context context, String eventId, String label) {
        onRandomEvent(context, eventId, label, DEFAULT_RANDOM_RATE);
    }

    // Rate is random collect rate, if the rate is m, then the event collect rate is 1/m.
    public void onRandomEvent(Context context, String eventId, String label, int rate) {
        Assert.isTrue(mIsInitialized);
        if (isRandomCollect(rate)) {
            for (IAnalyticsCollector collector : mAnalyticsCollectors)
                collector.onEvent(context, eventId, label);
        }
    }

    @Override
    public void onEvent(Context context, String eventId, HashMap<String, String> map) {
        Assert.isTrue(mIsInitialized);
        for (IAnalyticsCollector collector : mAnalyticsCollectors)
            collector.onEvent(context, eventId, map);
    }

    public void onRandomEvent(Context context, String eventId, HashMap<String, String> map) {
        onRandomEvent(context, eventId, map, DEFAULT_RANDOM_RATE);
    }

    // Rate is random collect rate, if the rate is m, then the event collect rate is 1/m.
    public void onRandomEvent(Context context, String eventId, HashMap<String, String> map, int rate) {
        Assert.isTrue(mIsInitialized);
        if (isRandomCollect(rate)) {
            for (IAnalyticsCollector collector : mAnalyticsCollectors)
                collector.onEvent(context, eventId, map);
        }
    }

    @Override
    public void onException(Context context, Throwable exception) {
        Assert.isTrue(mIsInitialized);
        for (IAnalyticsCollector collector : mAnalyticsCollectors)
            collector.onException(context, exception);
    }

    @Override
    public void trackInstalledApp(Context context, boolean includeSysApp) {
        Assert.isTrue(mIsInitialized);
        for (IAnalyticsCollector collector : mAnalyticsCollectors)
            collector.trackInstalledApp(context, includeSysApp);
    }

    private static boolean isRandomCollect(int rate) {
        Random random = new Random();
        return (random.nextInt(rate) == 0);
    }
}
